#ifndef xpack_adapter_format_output_stream
#define xpack_adapter_format_output_stream
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::adapter_format_output_stream::inc
#include"configure/limit.hpp"
#include"define/base_type.hpp"
#include"define/classify.hpp"
#include"lang/cxx/logger_helper.hpp"
#include"lang/cxx.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"meta/is_origin_string.hpp"
#include"utils/memory.hpp"
#include"utils/mix_item.hpp"
#include"utils/static_length_of.hpp"
#pragma pop_macro("xuser")

namespace mixc::adapter_format_output_stream{
    template<class type_t>
    concept is_format_cxx = inc::is_cxx<type_t> or inc::is_origin_string<type_t>;

    template<class final_t>
    xstruct(
        xtmpl(format_output_stream, final_t)
    )
    private:
        template<bool is_non_secret_v, class a0_t, class ... args_t>
        uxx xreflect_core(inc::c08 fmt, a0_t const & first, args_t const & ... list) const {
            char buffer[inc::limit::adapter_format_output_stream_buffer];
            auto need_free      = false;

            inc::mix_item<char> items[] = { first, list... };
            inc::c08            result;
            auto alloc          = [&](uxx length){
                if (length < inc::static_length_of(buffer)){
                    return buffer;
                }
                else{
                    need_free   = true;
                    return inc::memory::alloc<char>(xsizeof(char) * length);
                }
            };

            if constexpr (is_non_secret_v){
                result          = fmt.logger_helper_non_secret(items, alloc);
            }
            else{
                result          = fmt.logger_helper(items, alloc);
            }

            auto length         = result->length();
            auto impl           = (final_t *)this;
            impl->output_text_core(result);

            if (need_free){
                inc::memory::free<char>(asciis(result), xsizeof(char) * length);
            }
            return length;
        }

    public:
        template<class a0_t, class ... args_t>
        uxx xreflect(inc::c08 fmt, a0_t const & first, args_t const & ... list) const {
            return this->template xreflect_core<false>(fmt, first, list...);
        }

        template<class a0_t, class ... args_t>
        uxx xreflect_non_secret(inc::c08 fmt, a0_t const & first, args_t const & ... list) const {
            return this->template xreflect_core<true>(fmt, first, list...);
        }

        template<class a0_t, class ... args_t>
        uxx xreflect_line(inc::c08 fmt, a0_t const & first, args_t const & ... list) const {
            return this->template xreflect_core<false>(fmt, first, list...);
        }

        template<class a0_t, class ... args_t>
        uxx xreflect_line_non_secret(inc::c08 fmt, a0_t const & first, args_t const & ... list) const {
            return this->template xreflect_core<true>(fmt, first, list...);
        }

        #define xreflect(...)                   xreflect(# __VA_ARGS__ ",", __VA_ARGS__)
        #define xreflect_non_secret(...)        xreflect_non_secret(# __VA_ARGS__ ",", __VA_ARGS__)
        #define xreflect_line(...)              xreflect_line(#__VA_ARGS__ "," xlocal_endl, __VA_ARGS__)
        #define xreflect_line_non_secret(...)   xreflect_line_non_secret(#__VA_ARGS__ "," xlocal_endl, __VA_ARGS__)

    private:
        template<bool is_non_secret_v, class ... args_t>
        uxx write_core(inc::c08 fmt, args_t && ... list) const {
            char buffer[inc::limit::adapter_format_output_stream_buffer];
            auto total_length       = uxx{};
            auto alloc              = [&](uxx length){
                if (length < inc::static_length_of(buffer)){
                    buffer[length]  = '\0';
                    return buffer;
                }
                else{
                    total_length    = length + 1;
                    auto mem        = inc::memory::alloc<char>(xsizeof(char) * total_length);
                    mem[length]     = '\0';
                    return mem;
                }
            };

            inc::c08 result;

            if constexpr (is_non_secret_v){
                result              = fmt.format_non_secret(xforward(list)..., alloc);
            }
            else{
                result              = fmt.format(xforward(list)..., alloc);
            }

            auto impl               = (final_t *)this;
            impl->output_text_core(result);

            if (total_length != 0){
                inc::memory::free<char>((char *)(result), xsizeof(char) * total_length);
            }
            return result->length;
        }

    public:
        template<class ... args_t>
        uxx write(inc::c08 fmt, args_t && ... list) const {
            return this->template write_core<false>(fmt, xforward(list)...);
        }

        template<class ... args_t>
        uxx write_non_secret(inc::c08 fmt, args_t && ... list) const {
            return this->template write_core<true>(fmt, xforward(list)...);
        }

        template<class a0_t, class ... args_t>
        requires(is_format_cxx<a0_t> == false)
        uxx write(a0_t && first, args_t && ... list){
            return this->template write_core<false>("", xforward(first), xforward(list)...);
        }

        template<class a0_t, class ... args_t>
        requires(is_format_cxx<a0_t> == false)
        uxx write_non_secret(a0_t && first, args_t && ... list){
            return this->template write_core<true>("", xforward(first), xforward(list)...);
        }

        template<class ... args_t>
        uxx write_line(args_t && ... list){
            return this->write(xforward(list)..., xlocal_endl);
        }

        template<class ... args_t>
        uxx write_line_non_secret(args_t && ... list){
            return this->write_non_secret(xforward(list)..., xlocal_endl);
        }

        template<class a0_t, class ... args_t>
        requires(is_format_cxx<a0_t> == false)
        uxx write_line(a0_t && first, args_t && ... list){
            return this->write("", xforward(first), xforward(list)..., xlocal_endl);
        }

        template<class a0_t, class ... args_t>
        requires(is_format_cxx<a0_t> == false)
        uxx write_line_non_secret(a0_t && first, args_t && ... list){
            return this->write_non_secret("", xforward(first), xforward(list)..., xlocal_endl);
        }
    $
}

#endif

xexport(mixc::adapter_format_output_stream::format_output_stream)
